/**
 *  Copyright 20.07.2012 oliver.keusemann@googlemail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package de.xelerity.geolessi.srv.impl.haltestelle.bahn;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.ParsingException;
import nu.xom.ValidityException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.xelerity.geolessi.preferences.Preferences;
import de.xelerity.geolessi.srv.CacheService;
import de.xelerity.geolessi.srv.InfoProvider;
import de.xelerity.geolessi.srv.InfoProvider.HALTESTELLENINFOPROVIDER;
import de.xelerity.geolessi.srv.ServiceProvider;
import de.xelerity.geolessi.srv.haltestelle.LinienProHaltestelleGetterI;
import de.xelerity.geolessi.srv.mixed.URLGenerator;
import de.xelerity.geolessi.srv.mixed.WSCallerI;
import de.xelerity.geolessi.srv.poi.HalteStellenGetterFacadeI;
import de.xelerity.geolessi.types.mixed.Koordinate;
import de.xelerity.geolessi.types.poi.HalteStelle;
import de.xelerity.geolessi.types.poi.HalteStellenListe;
import de.xelerity.geolessi.types.poi.HaltestellenIDProvider;
import de.xelerity.geolessi.types.verbindung.Linie;
import de.xelerity.geolessi.types.verbindung.Linien;
import de.xelerity.geolessi.types.verbindung.Richtung;
import de.xelerity.helper.StringFunktionen;

public class LinienProHaltestelleGetter implements LinienProHaltestelleGetterI {

	static java.util.HashSet<String> A = new java.util.HashSet<String>();

	private Log log = LogFactory.getLog(LinienProHaltestelleGetter.class);

	static CacheService<String> cacheService = null;

	private String getDBInfo(String pHalteStellenID) throws Exception {

		String[] lCheckTimes = { "07:00", "18:00", };

		String callRes = "";
		for (String lTIME : lCheckTimes) {

			String URL = setUpUrl(pHalteStellenID, lTIME);

			WSCallerI wsCaller2 = ServiceProvider.getWSCaller();

			if (Preferences.useProxy) {
				wsCaller2.addProperty("PROXYHOST", Preferences.Proxy);
				wsCaller2.addProperty("PROXYPORT", Preferences.ProxyPort + "");
			}

			byte[] callResB = wsCaller2.call(URL);

			callRes = callRes + new String(callResB, Preferences.ENC_ISO);
		}

		return callRes;

	}

	public Linien getLinien(List<String> pHalteStellenIDs) throws Exception {

		if (pHalteStellenIDs == null || pHalteStellenIDs.size() == 0) {
			log.error("Argument is empty, getLinien, return empty list");
			return new Linien();
		}

		if (cacheService == null) {
			cacheService = new CacheService<String>("Linien.class.String");
		}

		String callRes = "";

		for (String lHalteStellenID : pHalteStellenIDs) {
			int hsHash = lHalteStellenID.hashCode();
			String CStr = cacheService.get(hsHash);
			if (CStr != null) {
				log.info("Get cached 'Journey'-Info for HS:" + lHalteStellenID);
			} else {
				CStr = getDBInfo(lHalteStellenID);
				cacheService.put(hsHash, (CStr != null && CStr.trim().length() > 0) ? CStr : null);
			}

			callRes = callRes + CStr;
		}

		Linien lAlleLinien = new Linien();

		// <Journey fpTime="22:53" fpDate="19.07.12" delay="-"
		// targetLoc="SSB-Zentrum, Stuttgart" dirnr="559549" prod="STB   U8#STB"
		// dir="SSB-Zentrum, Stuttgart" administration="vvsSTB" is_reachable="0"
		// delayReason=" "/>
		// System.out.println(callRes);

		Document doc = null;

		try {
			Builder parser = new Builder(false);
			doc = parser.build("<xml>" + callRes + "</xml>", "http://www.example.org/");
		} catch (ValidityException ex) {
			doc = ex.getDocument();
		} catch (ParsingException ex) {
			log.error(ex.getMessage() + ": malformed '<Journey'-Format", ex);
			throw new Exception(ex.getMessage() + ": malformed '<Journey'-Format");
		}

		HashMap<Integer, Linie> lTmpLinienHash = new HashMap<Integer, Linie>();
		Pattern regex2 = Pattern.compile("dirnr=\"(.+?)\"", Pattern.CASE_INSENSITIVE);
		Pattern regex3 = Pattern.compile("prod=\"(.+?)\"", Pattern.CASE_INSENSITIVE);
		Pattern regex4 = Pattern.compile("targetLoc\\s*=\\s*\"(.+?)\"", Pattern.CASE_INSENSITIVE);

		try {
			Element E = doc.getRootElement();
			for (int i = 0; i < E.getChildCount(); i++) {

				Linie lLinie = new Linie();
				String str = E.getChild(i).toXML();

				String dirnr = "";
				try {
					Matcher regexMatcher2 = regex2.matcher(str);
					if (regexMatcher2.find()) {
						dirnr = regexMatcher2.group(1);
						dirnr = dirnr.replaceAll("\\s+", " ");

					}
				} catch (PatternSyntaxException ex) {
					log.error(ex.getMessage(), ex);
				}

				String prod = "";
				try {
					Matcher regexMatcher3 = regex3.matcher(str);
					if (regexMatcher3.find()) {
						prod = regexMatcher3.group(1);
						prod = prod.replaceAll("\\s+", " ");
						parseProd(lLinie, prod);

					}
				} catch (PatternSyntaxException ex) {
					log.error(ex.getMessage(), ex);
				}

				String target = "";
				try {
					Matcher regexMatcher4 = regex4.matcher(str);
					if (regexMatcher4.find()) {
						target = regexMatcher4.group(1);
						lLinie.addDirection(target, dirnr);
					}
				} catch (PatternSyntaxException ex) {
					log.error(ex.getMessage(), ex);
				}

				if (lTmpLinienHash.containsKey(lLinie.hashCode())) {
					// Linie gibbet schon
					lLinie = lTmpLinienHash.get(lLinie.hashCode());
					lLinie.addDirection(target, dirnr);
				} else {
					lLinie.addDirection(target, dirnr);
					lTmpLinienHash.put(lLinie.hashCode(), lLinie);
				}
			}

			for (Linie L : lTmpLinienHash.values()) {
				lAlleLinien.add(L);
			}

		} catch (Throwable ex) {
			log.error(ex.getMessage(), ex);
			return new Linien();
		}

		return lAlleLinien;
	}

	private void parseProd(Linie pLinie, String pProd) {
		if (StringFunktionen.isEmptyTrimed(pProd) || pLinie == null) {
			return;
		}

		Linie L = Linie.parseLinienInfo(pProd);
		if (L != null) {
			pLinie.setLinienTyp(L.getLinienTyp());
			pLinie.setNummer(L.getNummer());
			return;
		}
		log.error("Linienbezeichner '" + pProd + "' kann nicht zugeordnet werden (type, liniennummer). Code ergaenzen!");
	}

	private String setUpUrl(String DBHalteStelleID, String pTime) throws Exception {
		if (DBHalteStelleID == null || DBHalteStelleID.trim().length() <= 0) {
			throw new IllegalArgumentException("DBHalteStelleID nicht (korrekt) gesetzt");
		}

		URLGenerator urlGenerator = new URLGenerator("mobile.bahn.de", "/bin/mobil/stboard.exe/dn");

		// http://mobile.bahn.de/bin/mobil/stboard.exe/dn?productsFilter=1111111111&boardType=dep&disableEquivs=yes&maxJourneys=50&start=yes&input=8000096

		urlGenerator.addParameter("productsFilter", "000011011");
		urlGenerator.addParameter("boardType", "dep");

		urlGenerator.addParameter("disableEquivs", "yes"); //
		urlGenerator.addParameter("maxJourneys", "100");
		urlGenerator.addParameter("start", "yes");
		urlGenerator.addParameter("L", "vs_java3");
		urlGenerator.addParameter("input", DBHalteStelleID.trim());
		urlGenerator.addParameter("time", pTime);

		return urlGenerator.getURL();

	}

	public static void main(String[] args) {

		Log log1 = LogFactory.getLog(LinienProHaltestelleGetter.class);

		try {

			HalteStellenGetterFacadeI halteStellenInfoProvider = InfoProvider.getHalteStellenInfoProvider();
			// HalteStellenListe halteStellen = halteStellenInfoProvider.getHalteStellen(new
			// Koordinate(48.784261, 9.181607), 4000,
			// 0);

			HalteStellenListe halteStellen = halteStellenInfoProvider.getHalteStellen(Koordinate.STADTMITTE, 100, 0);

			for (HalteStelle HS : halteStellen.getHalteStellen()) {

				List<String> iDs = HS.getIDs(HaltestellenIDProvider.BAHN);
				String HSIDS = "";
				for (String S : iDs) {
					HSIDS = HSIDS + ", " + S;
				}

				System.out.println("\n" + HS.getTitle() + " -- " + HS.getAddressbez() + " -- " + HSIDS.replaceAll("^,\\s+", ""));
				System.out
						.println("---------------------------------------------------------------------------------------------------------");
				LinienProHaltestelleGetterI linienProHaltestelleProvider = InfoProvider
						.getLinienProHaltestelleProvider(HALTESTELLENINFOPROVIDER.BAHN);

				if (HS.hasID(HaltestellenIDProvider.BAHN)) {
					List<Linie> linien = linienProHaltestelleProvider.getLinien(HS.getIDs(HaltestellenIDProvider.BAHN));

					for (Linie L : linien) {
						System.out.println("Line: " + L.getLinienTypAsString() + " " + L.getNummer());
						for (Richtung dirs : L.getDirections()) {
							System.out.println("  ->" + dirs.getDirection() + " (" + dirs.getDirectionNr() + ")");
						}
					}

				} else {
					System.out.println("*** BAHNID NOT FOUND");
				}
			}

			Iterator<String> iterator = A.iterator();
			while (iterator.hasNext()) {
				String next = iterator.next();
				System.out.println(next);
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

// http://mobile.bahn.de/bin/mobil/stboard.exe/dn?productsFilter=1111111111&boardType=dep&disableEquivs=yes&maxJourneys=50&start=yes&L=vs_java3&input=562250